#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <stdint.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include "socket_sub_thread.h"
#include "socket_thread.h"
#include "usr_typedef.h"
#include "timet.h"
#include "main.h"
#include "zlog.h"


extern pthread_mutex_t 		daq_mutex;
extern pthread_cond_t 		daq_cond;

socket_info					socket_infd[SOCKET_SER];		//线程池


void *socket_thread(void *arc)
{
	int sockfd, optval, new_fd, pth_ret, sock_id = 0;		// 监听socket: sock_fd,数据传输socket: new_fd
	uint16_t port;
	struct sockaddr_in server_addr;							// 本机地址信息
	struct sockaddr_in client_addr;							// 客户地址信息
	uint32_t client_addr_len;
	char dot_dec_str[INET_ADDRSTRLEN];
	char connect_state[100];

	struct timeval timeout;
    timeout.tv_sec = SOCKET_TIMEOUT;
    timeout.tv_usec = 0;

	thread_status *s = NULL;

	if(arc == NULL)
		return NULL;

	port = sys_cfg.socket_port;

	if(port == 0)
		port = SOCKET_PORT_NUMBER;

	//初始化sockaddr_in结构，将地址内字节置零,然后填充服务器IP信息
	memset(&(server_addr), 0x00, sizeof(struct sockaddr_in));
	server_addr.sin_family = PF_INET;
	server_addr.sin_port = htons(port); 
	server_addr.sin_addr.s_addr = INADDR_ANY;  					//监听服务器所有IP地址

	if (sys_cfg.socket_type == TCP) {
		if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == FAILURE) {		//申请SOCKET,IPV4 流模式
			dzlog_error("socket stream establish failed!");
			printf("socket stream establish failed!\n");
			pthread_exit((void *)"socket stream establish failed!");
		}
		optval = 1;													//必须设置为1
		if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == FAILURE) {
			dzlog_error("setsockopt reuseaddr failed!");
			printf("setsockopt reuseaddr failed!\n");
			pthread_exit((void *)"setsockopt reuseaddr failed!\n");
		}

		socklen_t len = sizeof(timeout);

		if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, len) == FAILURE) {
			dzlog_error("setsockopt resv timeout failed!");
			printf("setsockopt resv timeout failed!\n");
			pthread_exit((void *)"setsockopt resv timeout failed!\n");
    	}
		/*
    	if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len) == FAILURE) {
			dzlog_error("setsockopt send timeout failed!");
			printf("setsockopt send timeout failed!\n");
			pthread_exit((void *)"setsockopt send timeout failed!\n");
    	}
		*/

		//绑定IP,PORT
		if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == FAILURE) {
			dzlog_error("tcp ip address bind failed!");
			printf("tcp ip address bind failed!\n");
			pthread_exit((void *)"tcp ip address bind failed!\n");
		}

		if (listen(sockfd, SOCKET_LISTEN_NUM) == FAILURE) {
			dzlog_error("tcp socket listen establish failed!");
			printf("tcp socket listen establish failed!\n");
			pthread_exit((void *)"tcp socket listen establish failed!\n");
		}
	}else {		//UDP and others
		if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == FAILURE) {		//申请SOCKET,IPV4 数据报模式
			dzlog_error("socket dgram establish failed!");
			printf("socket dgram establish failed!\n");
			pthread_exit((void *)"socket dgram establish failed!");
		}
		optval = 1;													//必须设置为1
		if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == FAILURE) {
			dzlog_error("setsockopt reuseaddr failed!");
			printf("setsockopt reuseaddr failed!\n");
			pthread_exit((void *)"setsockopt reuseaddr failed!\n");
		}
		if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == FAILURE) {
			dzlog_error("udp ip address bind failed!");
			printf("udp ip address bind failed!\n");
			pthread_exit((void *)"udp ip address bind failed!\n");
		}
	}
	
	s = (thread_status*)arc;
	s->status = TS_ALIVE;
	printf("tcp thread initial is complete!\n");
	
	while(s->status) {
		if (sys_cfg.socket_type == TCP) {
			client_addr_len = sizeof(struct sockaddr_in);
			if((new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len)) == FAILURE) {	//接受请求
				sleep(SOCKET_REACCEPT_DELAY);
				continue;
				printf("accept faild, tcp is busy!\n");
			}
			sprintf(connect_state, "server: got connection from ip addr %s", (char *)inet_ntop(AF_INET, 
					&client_addr.sin_addr, dot_dec_str, sizeof(dot_dec_str)));
			printf("%s\n", connect_state);
			dzlog_info("%s", connect_state);
		}
		
		//fmod()用来对浮点数进行取模(求余)fmod(x,y) x 除以 y 的余数
		sock_id = fmod(sock_id, SOCKET_SER);
		socket_infd[sock_id].new_fd 	= new_fd;
		socket_infd[sock_id].status 	= TS_ALIVE;
		socket_infd[sock_id].fd_time	= get_time_dbc();
		pth_ret = pthread_create(&socket_infd[sock_id].tid, NULL, socket_sub_thread, &socket_infd[sock_id]);
		if(pth_ret == 0)
			//在线程创建成功后使用pthread_detach分离子线程，这样就可以在子线程退出后自动回收子线程资源了
			pthread_detach(socket_infd[sock_id].tid);
		else
			break;
		
		sock_id++;
	}	
	close(sockfd);
	dzlog_notice("tcp or udp server: quit!!!");
	printf("tcp or udp server: quit!!!\n");
	s->status = TS_TERMINATED;
	pthread_exit(arc);
}


//for tcp thread test
/*
void *tcp_thread(void *arc)
{
	thread_status *s = NULL;

	printf("tcp thread initial is complete!\n");
	if(arc == NULL)
		return NULL;

	s = (thread_status*)arc;
	s->status = TS_ALIVE;

	while (s->status) {
		pthread_cond_wait(&daq_cond, &daq_mutex);
		//sleep(5);
		printf("tcp thread!\n");
	}

	printf("TCP server:quit \n");
	pthread_exit((void *)1);
}
*/
